//
// Created by hkkzzxz on 24-9-1.
//

#include "RedisConnectionPool.h"

std::shared_ptr<redisContext> RedisConnectionPool::createConnection() {
    redisContext *context = redisConnect(RedisAddress, port);
    if (context == NULL || context->err) {
        if (context) {
            redisFree(context);
        }
        consoleLogger->error("Failed to create Redis connection");
        fileLogger->error("Failed to create Redis connection");
        throw;
    }
    return std::shared_ptr<redisContext>(context, [](redisContext *context) {
        try {
            redisFree(context);
        }
        catch (const std::exception &e) {
            std::cerr << "Failed to close Redis connection: " << e.what() << std::endl;
        }
        delete context;
    });
}

RedisConnectionPool::RedisConnectionPool() {
    for (int i = 0; i < maxPoolSize; i++) {
        std::shared_ptr<redisContext> conn(createConnection());
        if (conn) {
            pool_.push(conn);
        }
    }
}

RedisConnectionPool::~RedisConnectionPool() {
    std::lock_guard<std::mutex> lock(mutex_);
    while (!pool_.empty()) {
        std::shared_ptr<redisContext> conn = pool_.front();
        pool_.pop();
        if (conn) {
            redisFree(conn.get());
        }
    }
}

std::shared_ptr<redisContext> RedisConnectionPool::getConnection() {
    std::unique_lock<std::mutex> lock(mutex_);
    // 如果连接池为空，则等待有可用连接或超时
    while (pool_.empty()) {
        if (cv_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) {
            // 如果等待超时，则创建一个新的连接
            consoleLogger->warn("Connection timeout. Creating a new connection");
            fileLogger->warn("Connection timeout. Creating a new connection");
            return createConnection();
        }
    }

    std::shared_ptr<redisContext> conn = pool_.front();
    pool_.pop();

    try {
        if (conn == NULL || conn->err) {
            redisFree(conn.get());
            return createConnection();
        }
    }
    catch (const std::exception &e) {
        consoleLogger->error("Error while validating redis connection: {} ", e.what());
        fileLogger->error("Error while validating redis connection: {}", e.what());
        redisFree(conn.get());
        return createConnection();
    }

    return conn;
}

void RedisConnectionPool::releaseConnection(std::shared_ptr<redisContext> conn) {
    std::lock_guard<std::mutex> lock(mutex_);
    pool_.push(conn);
    cv_.notify_one();
}
